package org.onionframework.faces.extension;

import java.util.HashMap;
import java.util.Map;

import javax.faces.context.FacesContext;

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;
import org.springframework.stereotype.Component;

/**
 * 视图范围的bean作用域
 * 
 * 在一个bean上标记@Scope("view")或者在xml中指定scope="view"后，
 * 前端访问某个页面，页面要求创建该bean，然后，在当前页面没有发生
 * 整页的get/post，也就是whole page reload，的情况下，后台的这个
 * bean对象一直存在。
 * 
 * 典型的，例如在前端访问a.xhtml，要求使用viewScope的后台bean A，
 * 请求完成后，后台创建了一个A对象，然后再a.xhtml页面上发出Ajax请求
 * 的过程中，后台不再创建新的A对象，于是该对象中的状态可以复用
 * 
 * @author allan
 *
 */
@Component
public class ViewScope implements Scope{
	
	public final String VIEW_SCOPE_KEY = "SPRING_VIEW_SCOPE";
	
	@Override
	public Object get(String name, ObjectFactory<?> objectFactory) {
		
		if (FacesContext.getCurrentInstance().getViewRoot() != null) {
			Map<String, Object> viewScope = extractViewScope();
			
			if (viewScope.get(name) == null) {
				Object object = objectFactory.getObject();
				viewScope.put(name, object);
				return object;
			} else {
				return viewScope.get(name);
			}
		} else {
			return null;
		}
		
	}

	@SuppressWarnings("unchecked")
	private Map<String, Object> extractViewScope() {
		Map<String, Object> attributes = FacesContext.getCurrentInstance().getViewRoot().getViewMap();
		
		Map<String, Object> viewScope = null;
		
		if (!attributes.containsKey(VIEW_SCOPE_KEY)) {
			viewScope = new HashMap<String, Object>();
			attributes.put(VIEW_SCOPE_KEY, viewScope);
		} else {
			viewScope = (Map<String, Object>) attributes.get(VIEW_SCOPE_KEY);
		}
		return viewScope;
	}

	@Override
	public String getConversationId() {
		return null;
	}

	@Override
	public Object remove(String name) {
		if (FacesContext.getCurrentInstance().getViewRoot() != null) {
			Map<String, Object> viewScope = extractViewScope();
			return viewScope.remove(name);
		} else {
			return null;
		}
	}
	
	@Override
	public Object resolveContextualObject(String arg0) {
		// TODO Auto-generated method stub
		return null;
	}
	
	@SuppressWarnings("unchecked")
	public <T> T getBean(Class<T> clazz,String name){
		Map<String, Object> viewScope = extractViewScope();
		if(viewScope.containsKey("scopedTarget." + name))
			return (T)viewScope.get("scopedTarget." + name);
		else
			return (T)viewScope.get(name);
	}

	@Override
	public void registerDestructionCallback(String name, Runnable callback) {
		// TODO Auto-generated method stub
		
	}
}
